package com.ruixiang.asm;

import com.sun.org.apache.bcel.internal.generic.RETURN;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import org.junit.Test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author ruixinag
 * @description asm-demo
 * @create Created in 2022/1/20 11:00
 */
public class LeanAsm {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 生成asm
        ClassWriter cw = new ClassWriter(0);
        // 定义对象头,版本号,修饰符,全类名,签名,父类,实现的接口
        cw.visit(Opcodes.V1_8,Opcodes.ACC_PUBLIC,"com/ruixiang/HelloWorld",null,"java/lang/Object",null);
        // 添加方法:修饰符,方法名,描述符,签名,抛出的异常
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main",
                "([Ljava/lang/String;)V", null, null);
        // 执行指令:获取静态属性
        mv.visitFieldInsn(Opcodes.GETSTATIC,"java/lang/System","out","Ljava/io/PrintStream");
        // 加载常量
        mv.visitLdcInsn("helloworld");
        // 调用方法
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/io/PrintStream","println","(Ljava/lang/string;)V",false);
        // 返回
        mv.visitInsn(Opcodes.RETURN);
        // 设置栈大小和局部变量表大小
        mv.visitMaxs(2,1);
        //方法结束
        mv.visitEnd();
        //类完成
        cw.visitEnd();

        //生产字节数组
        byte[] bytes = cw.toByteArray();

        //使用自定义的classloader
        MyClassLoader cl = new MyClassLoader();

        // 加载生产的类
        Class<?> aClass = cl.defineClass("com.ruixiang.HelloWorld", bytes);
        // 反射main方法
        Method main = aClass.getMethod("main", String[].class);
        // 调用main方法
        main.invoke(null,new Object[]{new String[]{}});

    }

    static class MyClassLoader extends ClassLoader {
        public Class<?> defineClass(String name,byte[] b){
            return super.defineClass(name,b,0,b.length);
        }
    }


}
